#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <strings.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/epoll.h>
#include <errno.h>
#include <pthread.h>

#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10
#define PORT 8888

/* set fd to noblock*/
int setnoblocking(int fd)
{
	int old_option = fcntl(fd, F_GETFL);
	int new_option = old_option |O_NONBLOCK;
	fcntl(fd, F_SETFL,new_option);
	return old_option;
}

void addfd(int epollfd, int fd ,int enable_et)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN;
	if(enable_et)
	{
		event.events |= EPOLLET;
	}
	epoll_ctl(epollfd, EPOLL_CTL_ADD,fd, &event);
	setnoblocking(fd);
}

void LT(struct  epoll_event * events ,int number , int epollfd ,int listenfd)
{	
	int i;
	char buf[BUFFER_SIZE];
	for( i=0;i<number ;i++)
	{
		int sockfd = events[i].data.fd;
		if(sockfd == listenfd)
		{
			struct sockaddr_in client;
			socklen_t client_len = sizeof(client);
			int connfd =accept(listenfd ,(struct sockaddr *)&client , &client_len);
			addfd(epollfd, connfd, 0); //disable ET model;
			printf("client is connect!\n");
	
		}else if(events[i].events & EPOLLIN)
		{
			printf("event tigger once \n");
			memset(buf, '\0',BUFFER_SIZE);
			int ret =recv(sockfd, buf, BUFFER_SIZE-1 , 0);
			if(ret <0)
			{
				if(errno ==EAGAIN || errno == EWOULDBLOCK)
				{
					printf("read later \n");
					break;
				}
				close(sockfd);
				break;
			}else if(ret ==0)
			{
				close(sockfd);
			}else{
				printf("get %d byte if content : %s \n",ret ,buf);
			}
			
		}else{
			printf("something else happened \n");		
		}
	}
}


void ET(struct epoll_event *events ,int number , int epollfd ,int listenfd)
{
	char buf[BUFFER_SIZE];
	int i=0;
	for(i=0;i<number ;i++)
	{
		int sockfd = events[i].data.fd;
		if(sockfd == listenfd)
		{
			struct sockaddr_in client;
			socklen_t client_len = sizeof(client);
			int connfd =accept(listenfd ,(struct sockaddr *)&client , &client_len);
			addfd(epollfd, connfd, 1); //enable  ET model;
			
	
		}else if(events[i].events & EPOLLIN)
		{
			printf("event tigger once \n");
			
			while(1)
			{
				memset(buf, '\0',BUFFER_SIZE);
				int ret =recv(sockfd, buf, BUFFER_SIZE-1 , 0);
				if(ret <0)
				{
					if(errno ==EAGAIN || errno == EWOULDBLOCK)
					{
						printf("read later \n");
						break;
					}
					close(sockfd);
					break;
				}else if(ret ==0)
				{
					close(sockfd);
				}else{
					printf("get %d byte if content : %s \n",ret ,buf);
				}
			}
			
		}else{
			printf("something else happened \n");		
		}
	}
}


int main()
{
	struct sockaddr_in server;
	int ret;
	bzero(&server,sizeof(server));
	server.sin_family = AF_INET;
	inet_pton(AF_INET,"127.0.0.1",&server.sin_addr);
	server.sin_port = htons(PORT);
	
	int listenfd = socket(AF_INET, SOCK_STREAM , 0 );
	assert(listenfd>=0);
	ret = bind(listenfd, (struct sockaddr*)&server , sizeof(server));
	assert(ret != -1);
	ret = listen(listenfd , 5);
	assert(ret !=-1);
	
	struct epoll_event events[MAX_EVENT_NUMBER];
	int epollfd = epoll_create(5);
	assert(epollfd !=-1);
	addfd(epollfd, listenfd, 1);
	
	while(1)
	{
		int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER , -1);
		if(ret <0 )
		{
			printf("epoll failure \n");	
			break;
		}
		LT(events, ret , epollfd, listenfd);
		//ET(events, ret , epollfd, listenfd);		
	}
	
	close(listenfd);
	return 0;
}	
